package pl.polidea.nativebuffer;

import java.util.HashMap;

import android.graphics.Bitmap;

/**
 * The Class NativeBuffer allows to make use of native memory unavailable to
 * regular java applications.
 */
public class NativeBuffer {

    /** The bytes. */
    static int bytes;

    /** The pointers. */
    static HashMap<Integer, Integer> pointers = new HashMap<Integer, Integer>();

    static {
        System.loadLibrary("nativebuffer");
    }

    /**
     * Pushes the data outside managed heap. Allocates new buffer.
     * 
     * @param pixels
     *            the data
     * @param size
     *            the size
     * @return the int
     */
    private static native int setIntData(int[] pixels, int size);

    private static native int setBitmapData2(Bitmap bitmap);

    /**
     * Sets the data.
     * 
     * @param data
     *            the data
     * @param size
     *            the size
     * @return the int
     */
    private static native int setData(byte[] data, int size);

    /**
     * Pushes the data outside managed heap. Allocates new buffer.
     * 
     * @param pixels
     *            the pixels
     * @return the int
     */
    public static int setIntData(int[] pixels) {
        bytes += pixels.length * 4;
        int pointer = setIntData(pixels, pixels.length);
        pointers.put(pointer, pixels.length * 4);
        return pointer;
    }

    public static int setBitmapData(Bitmap bitmap) {
        bytes += bitmap.getRowBytes() * bitmap.getHeight();
        int pointer = setBitmapData2(bitmap);
        pointers.put(pointer, bitmap.getRowBytes() * bitmap.getHeight());
        return pointer;
    }

    /**
     * Sets the data.
     * 
     * @param data
     *            the data
     * @return the int
     */
    public static int setData(byte[] data) {
        bytes += data.length;
        int pointer = setData(data, data.length);
        pointers.put(pointer, data.length);
        return pointer;
    }

    /**
     * Gets the data from native memory.
     * 
     * @param pointer
     *            the pointer
     * @param size
     *            the size
     * @return the data
     */
    private static native int[] getIntData(int pointer, int size);

    /**
     * Gets the bitmap data.
     * 
     * @param pointer
     *            the pointer
     * @param bitmap
     *            the bitmap
     * @return the bitmap data
     */
    private static native void getBitmapData2(int pointer, Bitmap bitmap);

    /**
     * Gets the data.
     * 
     * @param pointer
     *            the pointer
     * @param size
     *            the size
     * @return the data
     */
    private static native byte[] getData(int pointer, int size);

    /**
     * Gets the int data.
     * 
     * @param pointer
     *            the pointer
     * @return the int data
     */
    public static int[] getIntData(int pointer) {
        int size = pointers.get(pointer) / 4;
        return getIntData(pointer, size);
    }

    public static void getBitmapData(int pointer, Bitmap bitmap) {
        getBitmapData2(pointer, bitmap);
    }

    /**
     * Gets the data.
     * 
     * @param pointer
     *            the pointer
     * @return the data
     */
    public static byte[] getData(int pointer) {
        int size = pointers.get(pointer);
        return getData(pointer, size);
    }

    /**
     * Deallocates native buffer. After deallocation the pointer becomes
     * invalid. Every memory block should be deallocated when unnecessary
     * 
     * @param pointer
     *            the pointer
     */
    private static native void free2(int pointer);

    /**
     * Free.
     * 
     * @param pointer
     *            the pointer
     */
    public static void free(int pointer) {
        int size = pointers.get(pointer);
        bytes -= size;
        pointers.remove(pointer);
        free2(pointer);
    }

    /**
     * Gets the amount of free native memory that can be used by native buffer.
     * 
     * @return the mem free in Kb
     */
    public static native int getMemFree();

    /**
     * Gets the amount of total native memory available on device.
     * 
     * @return the mem free in Kb
     */
    public static native int getMemTotal();

    /**
     * Gets the bytes.
     * 
     * @return the bytes
     */
    public static int getBytes() {
        return bytes;
    }
}
